home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Risc World 3
/
Risc World 3.iso
/
SOFTWARE
/
ISSUE6
/
PD
/
PDF
/
GuiLib
/
Task
/
c++
/
GuiRegister
< prev
next >
Wrap
Text File
|
2003-02-14
|
25KB
|
770 lines
//--------------------------------------------------------------------------
//
// Copyright (c) 2002, Colin Granville
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * The name Colin Granville may not be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//--------------------------------------------------------------------------
#include "GuiTargets.h"
#include "GuiTask.h"
#include "GuiToolbox.h"
#include "GuiWindow.h"
#include "ERROR.h"
#include <stdlib.h>
GuiEventTarget::~GuiEventTarget() {}
inline unsigned int monotonic_time() {return _swi(OS_ReadMonotonicTime,_RETURN(0));}
class Initialise
{
public:
Initialise();
private:
GUI_DECLARE_EVENT_TARGETS(Initialise);
Claim toolbox_error(GuiToolboxEvent &event,const GuiIdBlock&);
Claim quit_quit(GuiToolboxEvent &event,const GuiIdBlock&);
Claim default_redraw(GuiWimpPollBlock& blk,const GuiIdBlock&);
Claim default_key_press(GuiWimpPollBlock& blk,const GuiIdBlock&);
Claim quit_message(GuiWimpMessage&);
};
Initialise::Initialise()
{
new GuiToolboxTarget(0,GuiToolbox::Error::Event,this,Initialise::toolbox_error);
new GuiToolboxTarget(0,0x82a90+1,this,Initialise::quit_quit);
new GuiWimpTarget(0,GuiWimp_ERedrawWindow,this,Initialise::default_redraw);
new GuiWimpTarget(0,GuiWimp_EKeyPressed,this,Initialise::default_key_press);
new GuiMessageTarget(GuiWimp_MQuit,this,Initialise::quit_message);
}
//*********************************************************************
Claim Initialise::toolbox_error(GuiToolboxEvent &event,const GuiIdBlock&)
{
GuiToolbox::Error* err=(GuiToolbox::Error*)&event;
WARN((_kernel_oserror*)&err->errnum);
return CLAIM;
}
//*********************************************************************
Claim Initialise::quit_quit(GuiToolboxEvent&,const GuiIdBlock&)
{
exit(0);
return CLAIM;
}
//*********************************************************************
Claim Initialise::default_redraw(GuiWimpPollBlock& blk,const GuiIdBlock&)
{
GuiRedrawWindowBlock& rb = (GuiRedrawWindowBlock&)blk;
int more=0;
GuiWindow::redraw(rb,more);
while (more) GuiWindow::getRectangle(rb,more);
return CLAIM;
}
//*********************************************************************
Claim Initialise::default_key_press(GuiWimpPollBlock& blk,const GuiIdBlock&)
{
_swi(Wimp_ProcessKey,_IN(0),blk.keyPressed.keyCode);
return CLAIM;
}
//*********************************************************************
Claim Initialise::quit_message(GuiWimpMessage&)
{
exit(0);
return CLAIM;
}
//********************************************************************************
GuiIdBlock* id_block;
void GuiRegister::initialise(GuiIdBlock& id_blk)
{
if (id_block!=0) return;
id_block=&id_blk;
new Initialise;
}
//********************************************************************************
//********************************************************************************
class GuiNullEventRegisterItem
{
public:
GuiNullEventRegisterItem* next;
GuiNullEventRegisterItem* previous;
unsigned int interval;
unsigned int call_time;
GuiNullEventTarget* command;
int thread_count;
bool is_deleted() {return command==0;}
bool match(unsigned int null_time) {return !is_deleted() && call_time<=null_time;}
GuiNullEventRegisterItem* dispatch(GuiNullEventRegisterItem** first);
void remove(GuiNullEventRegisterItem** first)
{
if (thread_count)
{
if (command) {command->item=0;command=0;}
}
else
{
if (command) command->item=0;
if (next) next->previous=previous;
if (previous)
previous->next=next;
else
*first=next;
if (command) {command->item=0;command=0;}
delete this;
}
}
};
//********************************************************************************
GuiNullEventRegisterItem* GuiNullEventRegisterItem::dispatch(GuiNullEventRegisterItem** first)
{
thread_count++;
if (command) command->execute();
thread_count--;
GuiNullEventRegisterItem* next_item=next;
if (is_deleted() && thread_count==0) remove(first);
return next_item;
}
//********************************************************************************
class GuiNullEventRegister
{
public:
GuiNullEventRegister();
GuiNullEventRegisterItem* add(unsigned int interval,GuiNullEventTarget* command);
void remove(GuiNullEventRegisterItem*);
void dispatch();
unsigned int get_null_event_time() const {return null_event_time;}
unsigned int get_minimum_return_time() const {return minimum_return_time;}
void set_interval(GuiNullEventRegisterItem*,unsigned int interval);
operator const void*() const {return first;}
operator void*() {return first;}
bool operator!() const {return first==0;}
private:
GuiNullEventRegisterItem* first;
unsigned int null_event_time;
unsigned int minimum_return_time;
} null_event_register;
//********************************************************************************
GuiNullEventRegister::GuiNullEventRegister()
: first(0),
null_event_time(monotonic_time()),
minimum_return_time(null_event_time)
{
}
//********************************************************************************
void GuiNullEventRegister::dispatch()
{
null_event_time=monotonic_time();
GuiNullEventRegisterItem* p=first;
GuiNullEventRegisterItem* next;
unsigned int min_time=0xffffffff;
minimum_return_time=min_time;
while (p)
{
if (!p->is_deleted())
{
if (p->call_time<=null_event_time)
{
next = p->dispatch(&first);
p->call_time=null_event_time+p->interval;
if (p->call_time<min_time) min_time=p->call_time;
p=next;
}
else
{
if (p->call_time<min_time) min_time=p->call_time;
p=p->next;
}
}
else p=p->next;
}
if (min_time<minimum_return_time) minimum_return_time=min_time;
}
//********************************************************************************
GuiNullEventRegisterItem* GuiNullEventRegister::add(unsigned int interval,GuiNullEventTarget* command)
{
GuiNullEventRegisterItem* p=new GuiNullEventRegisterItem;
if (p)
{
p->interval=interval;
p->call_time=interval+null_event_time;
p->command=command;
p->thread_count=0;
if (p->call_time<minimum_return_time) minimum_return_time=p->call_time;
p->next=first;
p->previous=0;
if (p->next) p->next->previous=p;
first=p;
}
return p;
}
//********************************************************************************
void GuiNullEventRegister::remove(GuiNullEventRegisterItem* item)
{
if (item) item->remove(&first);
}
//********************************************************************************
void GuiNullEventRegister::set_interval(GuiNullEventRegisterItem* item,unsigned int interval)
{
if (item)
{
item->interval=interval;
unsigned int call_time=null_event_time+interval;
if (call_time<minimum_return_time) minimum_return_time=call_time;
}
}
//********************************************************************************
//********************************************************************************
GuiNullEventTarget::GuiNullEventTarget()
: item(0) {}
//********************************************************************************
GuiNullEventTarget::GuiNullEventTarget(unsigned int interval)
: item(0)
{
setInterval(interval);
}
//********************************************************************************
GuiNullEventTarget::~GuiNullEventTarget() {destroy();}
//********************************************************************************
void GuiNullEventTarget::setInterval(unsigned int interval)
{
if (item)
null_event_register.set_interval(item,interval);
else
item=null_event_register.add(interval,this);
}
//********************************************************************************
void GuiNullEventTarget::destroy()
{
if (item) null_event_register.remove(item);
}
//********************************************************************************
//********************************************************************************
//********************************************************************************
class GuiWimpRegisterItem
{
public:
GuiWimpRegisterItem* next;
GuiWimpRegisterItem* previous;
GuiObjectId id;
int event_code;
GuiWimpEventTarget* command;
int thread_count;
bool is_deleted() {return command==0;}
bool match(const GuiIdBlock& id_block) {return !is_deleted() &&
(id_block.self.id==id || id==NULL_GuiObjectId);}
GuiWimpRegisterItem* dispatch(GuiWimpPollBlock& wpb,const GuiIdBlock& id_block,GuiWimpRegisterItem** first);
void remove(GuiWimpRegisterItem** first)
{
if (thread_count)
{
if (command) {command->item=0;command=0;}
}
else
{
if (next) next->previous=previous;
if (previous)
previous->next=next;
else
*first=next;
delete this;
if (command) {command->item=0;command=0;}
}
}
};
//********************************************************************************
GuiWimpRegisterItem* GuiWimpRegisterItem::dispatch(GuiWimpPollBlock& wpb,const GuiIdBlock& id_block,
GuiWimpRegisterItem** first)
{
thread_count++;
Claim claim=(is_deleted())?DONT_CLAIM:command->execute(wpb,id_block);
thread_count--;
GuiWimpRegisterItem* next_item=next;
if (is_deleted() && thread_count==0) remove(first);
return (claim==DONT_CLAIM)?next_item:0;
}
//********************************************************************************
class GuiWimpRegister
{
public:
GuiWimpRegisterItem* add(int event_code,GuiObjectId,GuiWimpEventTarget*);
void remove(GuiWimpRegisterItem*);
void dispatch(int event_code,GuiWimpPollBlock& wpb,const GuiIdBlock& id_block);
private:
GuiWimpRegisterItem* event_list[32];
}wimp_register;
//********************************************************************************
void GuiWimpRegister::dispatch(int event_code,GuiWimpPollBlock& wpb,const GuiIdBlock& id_block)
{
if (event_code>=32) return;
GuiWimpRegisterItem** first=&event_list[event_code];
GuiWimpRegisterItem* p=*first;
while (p)
{
if (p->match(id_block))
p = p->dispatch(wpb,id_block,first);
else p=p->next;
}
}
//********************************************************************************
GuiWimpRegisterItem* GuiWimpRegister::add(int event_code,GuiObjectId id,GuiWimpEventTarget* command)
{
if (event_code>=32) return 0;
GuiWimpRegisterItem* p=new GuiWimpRegisterItem;
if (p)
{
p->id=id;
p->event_code=event_code;
p->command=command;
p->thread_count=0;
p->next=event_list[event_code];;
p->previous=0;
if (p->next) p->next->previous=p;
event_list[event_code]=p;
}
return p;
}
//********************************************************************************
void GuiWimpRegister::remove(GuiWimpRegisterItem* item)
{
if (item) item->remove(&event_list[item->event_code]);
}
//********************************************************************************
//********************************************************************************
GuiWimpEventTarget::GuiWimpEventTarget() : item(0) {}
GuiWimpEventTarget::GuiWimpEventTarget(const GuiObject* obj, int event_code)
: item(0)
{
setListener(obj,event_code);
}
//********************************************************************************
GuiWimpEventTarget::~GuiWimpEventTarget() {destroy();}
//********************************************************************************
void GuiWimpEventTarget::setListener(const GuiObject* object, int event_code)
{
if (item) destroy();
GuiObjectId object_id =(object)?object->id():NULL_GuiObjectId;
item=wimp_register.add(event_code,object_id,this);
}
//********************************************************************************
void GuiWimpEventTarget::destroy()
{
if (item) wimp_register.remove(item);
}
//********************************************************************************
//********************************************************************************
class GuiToolboxRegisterItem
{
public:
GuiToolboxRegisterItem* next;
GuiToolboxRegisterItem* previous;
int event_code;
GuiObjectId id;
GuiToolboxEventTarget* command;
int thread_count;
bool is_deleted() {return command==0;}
bool match(int event_code,const GuiIdBlock& id_block)
{return !is_deleted() &&
event_code==GuiToolboxRegisterItem::event_code &&
(id_block.self.id==id || id_block.ancestor.id==id || id==NULL_GuiObjectId);}
GuiToolboxRegisterItem* dispatch(GuiToolboxEvent& tbe,const GuiIdBlock& id_block,
GuiToolboxRegisterItem** first);
void remove(GuiToolboxRegisterItem** first)
{
if (thread_count)
{
if (command) {command->item=0;command=0;}
}
else
{
if (next) next->previous=previous;
if (previous)
previous->next=next;
else
*first=next;
if (command) {command->item=0;command=0;}
delete this;
}
}
};
//********************************************************************************
GuiToolboxRegisterItem* GuiToolboxRegisterItem::dispatch(GuiToolboxEvent& tbe,
const GuiIdBlock& id_block,GuiToolboxRegisterItem** first)
{
thread_count++;
Claim claim=(is_deleted())?DONT_CLAIM:command->execute(tbe,id_block);
thread_count--;
GuiToolboxRegisterItem* next_item=next;
if (is_deleted() && thread_count==0) remove(first);
return (claim==DONT_CLAIM)?next_item:0;
}
//********************************************************************************
class GuiToolboxRegister
{
public:
GuiToolboxRegisterItem* add(int event_code,GuiObjectId,GuiToolboxEventTarget*);
void remove(GuiToolboxRegisterItem*);
void dispatch(GuiToolboxEvent& tbe, const GuiIdBlock& id_block);
private:
unsigned int hash(unsigned int event) {return (event & 0xf) | ((event & 0xf00)>>4);}
GuiToolboxRegisterItem* event_list[256];
}toolbox_register;
//********************************************************************************
void GuiToolboxRegister::dispatch(GuiToolboxEvent& tbe, const GuiIdBlock& id_block)
{
GuiToolboxRegisterItem** first=&event_list[hash(tbe.eventCode)];
GuiToolboxRegisterItem* p=*first;
while (p)
{
if (p->match(tbe.eventCode,id_block))
p = p->dispatch(tbe,id_block,first);
else
p=p->next;
}
}
//********************************************************************************
GuiToolboxRegisterItem* GuiToolboxRegister::add(int event_code,GuiObjectId id,
GuiToolboxEventTarget* command)
{
GuiToolboxRegisterItem* p=new GuiToolboxRegisterItem;
if (p)
{
p->event_code=event_code;
p->id=id;
p->command=command;
p->thread_count=0;
unsigned int i=hash(event_code);
p->next=event_list[i];
p->previous=0;
if (p->next) p->next->previous=p;
event_list[i]=p;
}
return p;
}
//********************************************************************************
void GuiToolboxRegister::remove(GuiToolboxRegisterItem* item)
{
if (item) item->remove(&event_list[hash(item->event_code)]);
}
//********************************************************************************
//********************************************************************************
GuiToolboxEventTarget::GuiToolboxEventTarget() : item(0) {}
GuiToolboxEventTarget::GuiToolboxEventTarget(const GuiObject* obj, int event_code)
: item(0)
{
setListener(obj,event_code);
}
//********************************************************************************
GuiToolboxEventTarget::~GuiToolboxEventTarget() {destroy();}
//********************************************************************************
void GuiToolboxEventTarget::setListener(const GuiObject* object, int event_code)
{
if (item) destroy();
GuiObjectId object_id =(object)?object->id():NULL_GuiObjectId;
item=toolbox_register.add(event_code,object_id,this);
}
//********************************************************************************
void GuiToolboxEventTarget::destroy()
{
if (item) toolbox_register.remove(item);
}
//********************************************************************************
//********************************************************************************
//********************************************************************************
class GuiMessageRegisterItem
{
public:
GuiMessageRegisterItem* next;
GuiMessageRegisterItem* previous;
int message_code;
GuiMessageEventTarget* command;
int thread_count;
bool is_deleted() {return command==0;}
bool match(int message) {return !is_deleted() && message==message_code;}
GuiMessageRegisterItem* dispatch(GuiWimpMessage& wm,GuiMessageRegisterItem** first);
void remove(GuiMessageRegisterItem** first)
{
if (thread_count)
{
if (command) {command->item=0;command=0;}
}
else
{
if (next) next->previous=previous;
if (previous)
previous->next=next;
else
*first=next;
if (command) {command->item=0;command=0;}
delete this;
}
}
};
//********************************************************************************
GuiMessageRegisterItem* GuiMessageRegisterItem::dispatch(GuiWimpMessage& wm,
GuiMessageRegisterItem** first)
{
thread_count++;
Claim claim=(is_deleted())?DONT_CLAIM:command->execute(wm);
thread_count--;
GuiMessageRegisterItem* next_item=next;
if (is_deleted() && thread_count==0) remove(first);
return (claim==DONT_CLAIM)?next_item:0;
}
//********************************************************************************
class GuiMessageRegister
{
public:
GuiMessageRegisterItem* add(int message_code,GuiMessageEventTarget*);
void remove(GuiMessageRegisterItem*);
void dispatch(GuiWimpMessage& wm);
private:
unsigned int hash(int message_code) {return (message_code & 7) | ((message_code & 0x7c0)>>3);}
GuiMessageRegisterItem* event_list[256];
}message_register;
//********************************************************************************
void GuiMessageRegister::dispatch(GuiWimpMessage& wm)
{
GuiMessageRegisterItem** first=&event_list[hash(wm.hdr.actionCode)];
GuiMessageRegisterItem* p=*first;
while (p)
{
if (p->match(wm.hdr.actionCode))
p=p->dispatch(wm,first);
else p=p->next;
}
}
//********************************************************************************
GuiMessageRegisterItem* GuiMessageRegister::add(int message_code,GuiMessageEventTarget* command)
{
GuiMessageRegisterItem* p=new GuiMessageRegisterItem;
if (p)
{
p->message_code=message_code;
p->command=command;
p->thread_count=0;
unsigned int i=hash(message_code);
p->next=event_list[i];
p->previous=0;
if (p->next) p->next->previous=p;
event_list[i]=p;
}
return p;
}
//********************************************************************************
void GuiMessageRegister::remove(GuiMessageRegisterItem* item)
{
if (item) item->remove(&event_list[hash(item->message_code)]);
}
//********************************************************************************
//********************************************************************************
GuiMessageEventTarget::GuiMessageEventTarget() : item(0) {}
GuiMessageEventTarget::GuiMessageEventTarget(int message_code)
: item(0)
{
setListener(message_code);
}
//********************************************************************************
GuiMessageEventTarget::~GuiMessageEventTarget() {destroy();}
//********************************************************************************
void GuiMessageEventTarget::setListener(int message_code)
{
if (item) destroy();
item=message_register.add(message_code,this);
}
//********************************************************************************
void GuiMessageEventTarget::destroy()
{
if (item) message_register.remove(item);
}
//********************************************************************************
//********************************************************************************
//********************************************************************************
int mask;
void GuiRegister::dispatch(int event_code,GuiWimpPollBlock& poll_block)
{
if (id_block==0) return;
if (event_code<32)
{
switch (event_code)
{
case GuiWimp_ENull: null_event_register.dispatch();
break;
case 17:
case 18: message_register.dispatch(*(GuiWimpMessage*)&poll_block);
return;
}
wimp_register.dispatch(event_code,poll_block,*id_block);
}
else if (event_code==0x200)
toolbox_register.dispatch(*(GuiToolboxEvent*)&poll_block,*id_block);
}
//********************************************************************************
void GuiRegister::poll(int *ev_code, GuiWimpPollBlock* poll_blk, int* poll_w)
{
static GuiWimpPollBlock _poll_block;
int _event_code;
GuiWimpPollBlock* poll_block=(poll_blk)?poll_blk:&_poll_block;
int* event_code=(ev_code)?ev_code:&_event_code;
if (!null_event_register)
{
_swix(Wimp_Poll,_INR(0,1) | _IN(3) | _OUT(0),mask | 1,poll_block,poll_w,event_code);
}
else if (null_event_register.get_minimum_return_time()<=
null_event_register.get_null_event_time())
{
_swix(Wimp_Poll,_INR(0,1) | _IN(3) | _OUT(0),mask &~ 1,poll_block,poll_w,event_code);
}
else _swix(Wimp_PollIdle,_INR(0,3) | _OUT(0), mask &~ 1,poll_block,
null_event_register.get_minimum_return_time(),poll_w,event_code);
dispatch(*event_code,*poll_block);
}
//********************************************************************************
unsigned int GuiRegister::get_null_event_time()
{
return null_event_register.get_null_event_time();
}